package com.hsyt.pfc.support.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 证件识别工具类
 *
* @Author: wangze@hsyuntai.com
 */
public class IdCardOcrUtil {
    private static Logger log = LoggerFactory.getLogger(IdCardOcrUtil.class);

    @SuppressWarnings({"rawtypes", "unchecked"})
    public static Map aliOcr(String side, String img, String appcode, String host, String path) {
        String response = postAliOcr(side, img, appcode, host, path);
        log.info("ocr阿里返回数据：" + response);
        System.out.println("ocr阿里返回数据：" + response);
        if (StringUtils.isBlank(response)) {
            return null;
        }
        try {
            List<Map> outputs = (List<Map>) JSON.parseObject(response, Map.class).get("outputs");
            Map outputValue = (Map) outputs.get(0).get("outputValue");
            return JSON.parseObject((String) outputValue.get("dataValue"), Map.class);
        } catch (Exception e) {
            //可能返回的是运行错误信息，直接返回空，如kOtherError:Algorithm run failed  - back results are all empty
            return null;
        }
    }

    @SuppressWarnings({"rawtypes", "unchecked"})
    private static String postAliOcr(String side, String img, String appcode, String host, String path) {
        String method = "POST";
        Map<String, String> headers = new HashMap<String, String>();

        //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
        headers.put("Authorization", "APPCODE " + appcode);

        //根据API的要求，定义相对应的Content-Type
        headers.put("Content-Type", "application/json; charset=UTF-8");
        Map<String, String> querys = new HashMap<String, String>();

        //iamge参数
        Map image = new HashMap<String, String>();
        image.put("dataType", 50);
        image.put("dataValue", img);

        //side设置
        Map sideMap = new HashMap<String, String>();
        sideMap.put("side", side);

        //configure
        Map configure = new HashMap<String, String>();
        configure.put("dataType", 50);
        configure.put("dataValue", JSON.toJSONString(sideMap));

        //注意, inputs内是Array
        Map al = new HashMap<String, String>();
        al.put("image", image);
        al.put("configure", configure);

        List inpuList = new ArrayList<Map>();
        inpuList.add(al);

        JSONObject inputs = new JSONObject();
        inputs.put("inputs", inpuList);

        String bodys = JSON.toJSONString(inputs);
        //System.out.println(bodys);
        try {
            Long s = System.currentTimeMillis();
            log.info("ali http返回开始了");
            HttpResponse response = AliOcrUtil.doPost(host, path, method, headers, querys, bodys);
            log.info("ali http返回时间为:" + (System.currentTimeMillis() - s));
            return EntityUtils.toString(response.getEntity());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    @SuppressWarnings("restriction")
    public static String shangHaiHeHeOcr(String imgBase64, String urlString) {
        try {
            if (imgBase64 == null) //图像数据为空
                return null;
            Base64 base64 = new Base64();
            byte[] data = base64.decode(imgBase64);
            for (int i = 0; i < data.length; ++i) {
                if (data[i] < 0) {// 调整异常数据
                    data[i] += 256;
                }
            }
            URL url = new URL(urlString);
            HttpURLConnection con = (HttpURLConnection) url.openConnection();
            con.setDoOutput(true);
            con.setDoInput(true);
            con.setRequestMethod("POST");
            OutputStream out = con.getOutputStream();
            int len = data.length;
            out.write(data, 0, data.length);
            out.flush();
            out.close();
            int code = con.getResponseCode();
            System.out.println("code=" + code + " url=" + url);
            if (code == 200) {
                InputStream inputStream2 = con.getInputStream();
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                while ((len = inputStream2.read(data)) != -1) {
                    bos.write(data, 0, len);
                }
                inputStream2.close();
                return bos.toString();
            }
            con.disconnect();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }


    @SuppressWarnings("restriction")
    public static String baiduyunOcr(String imgBase64, String idCardSide, String url) {
        System.err.println("ocr请求地址:" + url);
        Base64 base64 = new Base64();
        byte[] data = null;
        try {
            data = base64.decode(imgBase64);
        } catch (Exception e1) {
            e1.printStackTrace();
        }
        for (int i = 0; i < data.length; ++i) {
            if (data[i] < 0) {// 调整异常数据
                data[i] += 256;
            }
        }
        String imgStr = Base64Util.encode(data);
        // 识别身份证正面id_card_side=front;识别身份证背面id_card_side=back;
        String params;
        String result = null;
        try {
            params = URLEncoder.encode("id_card_side", "UTF-8") + "=" + URLEncoder.encode(idCardSide, "UTF-8") + "&" + URLEncoder.encode("image", "UTF-8") + "=" + URLEncoder.encode(imgStr, "UTF-8");
            result = postBaiduOcrUrl(url, params);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(result);
        return result;
    }

    /**
     * 百度云ocr  post
     *
     * @Description ：
     * @Author : tengfei
     * @Date : 2018年1月8日 下午1:22:34
     */
    public static String postBaiduOcrUrl(String generalUrl, String params)
            throws Exception {
        String contentType = "application/x-www-form-urlencoded";
        String encoding = "UTF-8";
        if (generalUrl.contains("nlp")) {
            encoding = "GBK";
        }
        URL url = new URL(generalUrl);
        // 打开和URL之间的连接
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("POST");
        // 设置通用的请求属性
        connection.setRequestProperty("Content-Type", contentType);
        connection.setRequestProperty("Connection", "Keep-Alive");
        connection.setUseCaches(false);
        connection.setDoOutput(true);
        connection.setDoInput(true);

        // 得到请求的输出流对象
        DataOutputStream out = new DataOutputStream(
                connection.getOutputStream());
        out.write(params.getBytes(encoding));
        out.flush();
        out.close();

        // 建立实际的连接
        connection.connect();
        // 获取所有响应头字段
        // 定义 BufferedReader输入流来读取URL的响应
        BufferedReader in = null;
        in = new BufferedReader(new InputStreamReader(
                connection.getInputStream(), encoding));
        String result = "";
        String getLine;
        while ((getLine = in.readLine()) != null) {
            result += getLine;
        }
        in.close();
        System.err.println("result:" + result);
        return result;
    }

    //图片转化成base64字符串
    @SuppressWarnings("restriction")
    public static String GetImageStr(String imgFile) {//将图片文件转化为字节数组字符串，并对其进行Base64编码处理
        InputStream in = null;
        byte[] data = null;
        //读取图片字节数组  
        try {
            in = new FileInputStream(imgFile);
            data = new byte[in.available()];
            in.read(data);
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //对字节数组Base64编码  
        Base64 base64 = new Base64();
        return base64.encodeToString(data);//返回Base64编码过的字节数组字符串  
    }

    //base64字符串转化成图片  
    @SuppressWarnings("restriction")
    public static boolean GenerateImage(String imgStr, String imageUrl) {   //对字节数组字符串进行Base64解码并生成图片
        if (imgStr == null) //图像数据为空  
            return false;
        Base64 base64 = new Base64();
        try {
            // Base64解码
            byte[] b = base64.decode(imgStr);
            for (int i = 0; i < b.length; ++i) {
                if (b[i] < 0) {// 调整异常数据
                    b[i] += 256;
                }
            }
            // 生成jpeg图片
            OutputStream out = new FileOutputStream(imageUrl);
            out.write(b);
            out.flush();
            out.close();
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 封装 Face++ 身份证识别功能,返回身份证各字段信息，KV如下：
     * name: 姓名
     * sex : 性别
     * idCardNo: 身份证号
     * birthday: 生日
     * address: 住址
     * race: 民族
     * errorMsg: 错误信息, 调用出错时返回
     *
     * @param endpoint
     * @param appKey
     * @param appSecret
     * @param imgBase64Str
     * @return
     */
    public static Map<String, String> facePlusPlusIdCardOCR(String endpoint, String apiKey,
                                                            String apiSecret, String imgBase64Str) {
        RequestConfig requestConfig = RequestConfig.custom()
                .setSocketTimeout(5000)
                .setConnectTimeout(1000)
                .setConnectionRequestTimeout(500)
                .setStaleConnectionCheckEnabled(false)
                .build();
        HttpPost httpPost = new HttpPost(endpoint);
        List<NameValuePair> params = new ArrayList<>();
        params.add(new BasicNameValuePair("api_key", apiKey));
        params.add(new BasicNameValuePair("api_secret", apiSecret));
        params.add(new BasicNameValuePair("image_base64", imgBase64Str));
        Map<String, String> result = new HashMap<>();
        try {
            httpPost.setEntity(new UrlEncodedFormEntity(params));
        } catch (UnsupportedEncodingException e) {
            log.error("不支持 URL 编码");
            result.put("errorMsg", "请求编码异常");
            return result;
        }
        try {
            try (CloseableHttpClient client = HttpClients.custom().setDefaultRequestConfig(requestConfig).build()) {
                CloseableHttpResponse response = null;
                response = client.execute(httpPost);
                StatusLine statusLine = response.getStatusLine();
                if (statusLine.getStatusCode() != HttpStatus.SC_OK) {
                    log.warn("Face++ 服务返回异常状态码 => " + statusLine.getStatusCode());
                    result.put("errorMsg", "调用 OCR 服务返回异常结果(" + statusLine.getStatusCode() + "):" + statusLine.getReasonPhrase());
                    return result;
                }
                String respStr = EntityUtils.toString(response.getEntity(), "UTF-8");
                JSONObject idCardOcrResult = null;
                try {
                    idCardOcrResult = JSON.parseObject(respStr);
                } catch (Exception e) {
                    log.error("OCR 服务返回数据格式格式不正确", e);
                    result.put("errorMsg", "OCR 服务返回数据格式格式不正确");
                    return result;
                }
                String ocrErrorMsg = idCardOcrResult.getString("error_message");
                if (ocrErrorMsg != null) {
                    result.put("errorMsg", "身份证识别异常: " + ocrErrorMsg);
                    return result;
                } else {
                    JSONArray cards = idCardOcrResult.getJSONArray("cards");
                    if (cards == null || cards.size() == 0) {
                        result.put("errorMsg", "未识别出有效的身份证信息");
                        return result;
                    } else {
                        //识别出多张身份证只取第一张
                        JSONObject idCard = cards.getJSONObject(0);
                        log.info("识别到身份证 => " + idCard);
                        String side = idCard.getString("side");
                        if ("back".equals(side)) {
                            result.put("errorMsg", "识别到身份证国徽面,请拍照人像面后识别");
                            return result;
                        }
                        String name = idCard.getString("name");
                        if (StringUtil.isNotEmpty(name)) {
                            result.put("name", name);
                        }
                        String sex = idCard.getString("gender");
                        if (StringUtil.isNotEmpty(sex)) {
                            result.put("sex", sex);
                        }
                        String idCardNo = idCard.getString("id_card_number");
                        if (StringUtil.isNoneEmpty(idCardNo)) {
                            result.put("idCardNo", idCardNo);
                        }
                        String birthday = idCard.getString("birthday");
                        if (StringUtil.isNotEmpty(birthday)) {
                            result.put("birthday", birthday);
                        }
                        String address = idCard.getString("address");
                        if (StringUtil.isNotEmpty(address)) {
                            result.put("address", address);
                        }
                        String race = idCard.getString("race");
                        if (StringUtil.isNotEmpty(race)) {
                            result.put("race", race);
                        }
                        return result;
                    }
                }
            }
        } catch (IOException e) {
            log.error("获取 HTTP 连接异常");
            result.put("errorMsg", "网络连接异常或超时,请重试.");
            return result;
        }
    }

    @SuppressWarnings("unchecked")
    public static void main(String args[]) {

    }

}



